/******************************************************************************
*  author: hnuweiwei@gmail.com
*  version: 1.0
*  file: Verylong.cpp
*  date: 2014.07.09
*  description: long int realize
*  other:
******************************************************************************/

#include <iostream>  // declares cin, cout, >>, and <<
#include "verylong.h"  // declares very_long_int class
#include <algorithm>   // declares reverse
using namespace std;

very_long_int::very_long_int() {
} // default constructor

void very_long_int::initialize(unsigned n) {
	const short BASE = 10;

	digits.erase(digits.begin(), digits.end());
	do {
		digits.push_back(n % BASE);
		n = n / BASE;
	} while (n > 0);

	// digits is now in reverse order, so we reverse:
	reverse(digits.begin(), digits.end());
}

very_long_int::very_long_int(unsigned n) {
	initialize(n);
}

istream& operator>>(istream& instream, very_long_int& very_long) {
	const char LOWEST_DIGIT_CHAR = '0';
	const char HIGHEST_DIGIT_CHAR = '9';
	const char SENTINEL = 'x';

	char digit_char;
	very_long.digits.erase(very_long.digits.begin(), very_long.digits.end());
	cout << endl << "please input the digital end with " << SENTINEL << endl;
	do {
		// Loop invariant: Each digit read in so far has been appended to digits.
		instream >> digit_char;
		if ((LOWEST_DIGIT_CHAR <= digit_char)
				&& (digit_char <= HIGHEST_DIGIT_CHAR))
			very_long.digits.push_back(digit_char - LOWEST_DIGIT_CHAR);
	} // while
	while (digit_char != SENTINEL);
	cout << "endinput " << endl;
	return instream;
}

ostream& operator<<(ostream& outstream, const very_long_int very_long) {
	for (unsigned i = 0; i < very_long.digits.size(); i++)
		outstream << (int) very_long.digits[i];
	return outstream;
}

char very_long_int::least(unsigned i) const {
	if (i >= digits.size())
		return 0;
	else
		return digits[digits.size() - i - 1];
} // least

very_long_int very_long_int::operator+(const very_long_int& other_very_long) {
	int carry = 0, larger_size, partial_sum;

	very_long_int sum;

	if (digits.size() > other_very_long.digits.size())
		larger_size = digits.size();
	else
		larger_size = other_very_long.digits.size();

	for (unsigned i = 0; i < larger_size; i++) {
		// Loop invariant: The (i-1)st least significant digits in
		// the calling object and other_very_long have been added.
		partial_sum = least(i) + other_very_long.least(i) + carry;
		carry = partial_sum / 10;
		sum.digits.push_back(partial_sum % 10);
	} // for

	if (carry == 1)
		sum.digits.push_back(carry);
	reverse(sum.digits.begin(), sum.digits.end());
	return sum;
} // overloading +

bool very_long_int::operator<(const very_long_int &other_very_long) const {
	unsigned i;

	if (digits.size() < other_very_long.digits.size())
		return true;
	else if (digits.size() > other_very_long.digits.size())
		return false;
	else {
		for (i = 0; i < digits.size(); i++)

			// Loop invariant: The calling object and other_very_long
			//                 agree in the i-1 most significant digits.
			if (digits[i] < other_very_long.digits[i])
				return true;
			else if (digits[i] > other_very_long.digits[i])
				return false;

		return false; // the two objects have the same value
	} // the two objects have the same size
} // overloading  <

bool very_long_int::operator>(const very_long_int &other_very_long) const {
	return other_very_long < *this;
} // overloading  <

bool very_long_int::operator==(const very_long_int &other_very_long) const {
	return (!((*this) < other_very_long)) && (!(other_very_long < (*this)));
} // overloading ==

very_long_int very_long_int::fibonacci(unsigned n) {
	very_long_int previous(1), current(1), temp;
	unsigned i;
	if (n <= 2)
		initialize(1);
	else {
		for (i = 3; i <= n; i++) {
			temp = current;
			current = current + previous;
			previous = temp;
		} // for
		digits = current.digits;
	} // else
	return *this;
} // fibonacci